package com.atguigu.demojuc.chap02;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 高内聚 低耦合
 * 资源类：封装卖票的方法,由多个线程来调用
 */
class Ticket {
    private int number = 200; //数据  票数量     不能超卖(数量不能为负数)

    private ReentrantLock lock = new ReentrantLock(); //创建可重入的排他锁  默认：非公平锁

    //sync = fair ? new FairSync() : new NonfairSync();
    //private ReentrantLock lock = new ReentrantLock(true); // fair=true 公平锁   默认 fair=false 非公平锁

    /**
     * 卖票方法
     * 使用JUC提供的ReentrantLock
     */
    public void sale() {
        lock.lock(); //上锁
        if (number <= 0) {
            System.out.println("票已售罄");
            lock.unlock();
            return;
        }
        try {
            System.out.println(Thread.currentThread().getName() + "\t" + "开始售票:" + number);
            number--; //卖出一张    ++ -- 不是线程安全。
            //Thread.sleep(200);
            System.out.println(Thread.currentThread().getName() + "\t" + "剩余票数:" + number);

            check();


        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock(); //释放锁
        }
    }


    /**
     * 为了测试可重入锁，添加检查余票方法
     */
    public void check() {
        lock.lock();
        System.out.println("检查余票。。。。");
        lock.unlock();
    }
}

/**
 * 卖票应用程序：
 * <p>
 * 多线程编程代码模板(上)
 * 高内聚 低耦合
 * 线程 操作 资源类
 */
public class TicketDemo {

    public static void main(String[] args) {

        //资源对象
        Ticket ticket = new Ticket();

        //三个窗口同时卖20张票。
        //模拟卖票窗口
        new Thread(() -> {
            for (int i = 0; i < 2000; i++) {
                ticket.sale();  //线程 操作 资源类
            }
        }, "A").start();

        //模拟卖票窗口
        new Thread(() -> {
            for (int i = 0; i < 2000; i++) {
                ticket.sale();  //线程 操作 资源类
            }
        }, "B").start();

        //模拟卖票窗口
        new Thread(() -> {
            for (int i = 0; i < 2000; i++) {
                ticket.sale();  //线程 操作 资源类
            }
        }, "C").start();

    }
}
